package cn.edu.zut.score.service.impl;

import cn.edu.zut.score.core.cache.RedisCache;
import cn.edu.zut.score.core.constant.GroupInfoEnum;
import cn.edu.zut.score.core.constant.GroupTypeEnum;
import cn.edu.zut.score.core.constant.RoleEnum;
import cn.edu.zut.score.core.convert.UserConvert;
import cn.edu.zut.score.core.domain.ImportUser;
import cn.edu.zut.score.core.domain.PageResponse;
import cn.edu.zut.score.core.dto.request.GroupAddRequest;
import cn.edu.zut.score.core.dto.request.LoginRequest;
import cn.edu.zut.score.core.domain.RestResponse;
import cn.edu.zut.score.core.dto.request.PasswordRequest;
import cn.edu.zut.score.core.dto.request.UserPageRequest;
import cn.edu.zut.score.core.dto.response.UserResponse;
import cn.edu.zut.score.core.entity.Info;
import cn.edu.zut.score.core.entity.User;
import cn.edu.zut.score.core.util.MDUtil;
import cn.edu.zut.score.core.util.StringUtils;
import cn.edu.zut.score.mapper.UserMapper;
import cn.edu.zut.score.service.IClazzService;
import cn.edu.zut.score.service.IGroupService;
import cn.edu.zut.score.service.IMessageService;
import cn.edu.zut.score.service.IUserService;
import cn.edu.zut.score.service.biz.UserExcelService;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zby
 * @since 2021-06-25
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired(required = false)
    private UserMapper userMapper;

    @Autowired(required = false)
    private HttpServletRequest httpServletRequest;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IClazzService iClazzService;

    @Autowired
    private IMessageService iMessageService;

    @Autowired
    private IGroupService iGroupService;


    @Override
    public RestResponse<String> login(LoginRequest loginRequest) {
        LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
        qw.eq(User::getNoId, loginRequest.getUsername());
        User user = userMapper.selectOne(qw);
        if (user == null || !MDUtil.compare(loginRequest.getPassword(), user.getPassword())) {
            log.info("用户{}登录失败", loginRequest.getUsername());
            return RestResponse.fail("用户名或密码错误");
        }
        log.info("用户{}登录成功", loginRequest.getUsername());
        int hour = 2;
        if (loginRequest.getRemember()) {
            hour = 7 * 24;
        }
        String token = redisCache.setCurrentUser(user, hour);
        return RestResponse.success(token);
    }

    @Override
    public RestResponse<Map<String, String>> info() {
        String token = httpServletRequest.getHeader("Authorization");
        User currentUser = redisCache.getCurrentUser(token);
        HashMap<String, String> map = new HashMap<>();
        map.put("roles", String.valueOf(currentUser.getRole()));
        map.put("name", currentUser.getName());
        map.put("id", String.valueOf(currentUser.getId()));
        map.put("num", String.valueOf(iMessageService.getrUnReadNumById(currentUser.getId())));
        return RestResponse.success(map);
    }

    @Override
    public RestResponse<String> logout() {
        String token = httpServletRequest.getHeader("Authorization");
        redisCache.removeCurrentUser(token);
        return RestResponse.success("成功");
    }

    @Override
    public RestResponse<UserResponse> getUserById(Long id) {
        User user = this.getById(id);
        return RestResponse.success(UserConvert.INSTANCE.user2Response(user));
    }

    @Override
    public RestResponse<UserResponse> getCurrentUser() {
        String token = httpServletRequest.getHeader("Authorization");
        User currentUser = redisCache.getCurrentUser(token);
        return RestResponse.success(UserConvert.INSTANCE.user2Response(currentUser));
    }

    @Override
    public RestResponse<UserResponse> addTeacher(User teacher) {
        RestResponse<UserResponse> res = saveUser(teacher);
        UserResponse tea = res.getResult();
        GroupAddRequest groupAddRequest = new GroupAddRequest();
        groupAddRequest.setName(tea.getName() + "-个人小组");
        groupAddRequest.setType(GroupTypeEnum.person.getCode());
        groupAddRequest.setNumberId(tea.getId());
        groupAddRequest.setNumberType(GroupInfoEnum.leader.getCode());
        iGroupService.saveGroup(groupAddRequest);
        return res;
    }

    @Override
    public RestResponse<UserResponse> saveUser(User user) {
        if (user.getClazzId() != null && user.getRole().equals(RoleEnum.student.getCode())) {
            if (user.getId() == null) {
                iClazzService.addStudent(user.getClazzId());
                log.info("学生：{}为新增，班级人数加一", user.getName());
            } else {
                User stu = this.getById(user.getId());
                if (!stu.getClazzId().equals(user.getClazzId())) {
                    iClazzService.removeStudent(stu.getClazzId());
                    iClazzService.addStudent(user.getClazzId());
                    log.info("学生:{}班级修改，班级:{}人数减一，班级:{}人数加一", user.getId(), stu.getClazzId(), user.getClazzId());
                }
                log.info("学生:{}班级无变动", user.getId());
            }
        }
        if (user.getId() == null) {
            user.fillCreateInfo(httpServletRequest, redisCache);
        } else {
            user.fillUpdateInfo(httpServletRequest, redisCache);
        }
        this.saveOrUpdate(user);
        return RestResponse.success(UserConvert.INSTANCE.user2Response(user));
    }

    @Override
    public RestResponse<UserResponse> updateCurrentUser(User user, RoleEnum roleEnum) {
        String token = httpServletRequest.getHeader("Authorization");
        User currentUser = redisCache.getCurrentUser(token);
        user.setId(currentUser.getId());
        user.setRole(roleEnum.getCode());
        user.setPassword(currentUser.getPassword());
        redisCache.updateCurrentUser(token, user);
        return this.saveUser(user);
    }

    @Override
    public RestResponse<UserResponse> restCurrentUserPassword(PasswordRequest passwordRequest) {
        String token = httpServletRequest.getHeader("Authorization");
        User currentUser = redisCache.getCurrentUser(token);
        if (!MDUtil.compare(passwordRequest.getOldPassword(), currentUser.getPassword())) {
            log.info("用户{}修改密码失败：[当前密码输入错误]", currentUser.getId());
            return RestResponse.fail("当前密码输入错误");
        }
        if (MDUtil.compare(passwordRequest.getNewPassword(), currentUser.getPassword())) {
            log.info("用户{}修改密码失败：[新密码与当前密码一致]", currentUser.getId());
            return RestResponse.fail("新密码与当前密码一致");
        }
        currentUser.setPassword(MDUtil.encryption(passwordRequest.getNewPassword()));
        redisCache.removeCurrentUser(token);
        return this.saveUser(currentUser);
    }

    @Override
    public RestResponse<Long> deleteUserById(Long id) {
        User user = this.getById(id);
        if (user.getClazzId() != null) {
            iClazzService.removeStudent(user.getClazzId());
            log.info("删除用户:{}为学生，对应班级人数减一", id);
        }
        this.removeById(id);
        log.info("成功删除用户{}", id);
        return RestResponse.success(id);
    }

    @Override
    public RestResponse<Integer> deleteUsersById(List<Long> ids) {
        Integer sum = 0;
        for (Long id : ids) {
            User user = this.getById(id);
            if (user.getClazzId() != null) {
                iClazzService.removeStudent(user.getClazzId());
                log.info("删除用户:{}为学生，对应班级人数减一", id);
            }
            boolean deleted = userMapper.deleteById(id) > 0;
            if (deleted) {
                sum++;
                log.info("成功删除用户{}", id);
            }
        }
        return RestResponse.success(sum);
    }

    @Override
    public RestResponse<Integer> importUsers(InputStream file, RoleEnum roleEnum) {
        EasyExcel.read(file, ImportUser.class, new UserExcelService(this, iClazzService, roleEnum)).sheet().doRead();
        return RestResponse.success();
    }

    @Override
    public RestResponse<PageResponse<UserResponse>> queryUsers(UserPageRequest pageRequest) {

        Page<User> page = new Page<>(pageRequest.getPage(), pageRequest.getLimit());
        LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
        if (StringUtils.isNotNullOrBlank(pageRequest.getNoId()) && !"-1".equals(pageRequest.getNoId())) {
            qw.like(User::getNoId, pageRequest.getNoId());
        }
        if (StringUtils.isNotNullOrBlank(pageRequest.getName()) && !"-1".equals(pageRequest.getName())) {
            qw.like(User::getName, pageRequest.getName());
        }
        if (pageRequest.getRole() != null) {
            qw.eq(User::getRole, pageRequest.getRole());
        }
        if (pageRequest.getClazzId() != null) {
            qw.eq(User::getClazzId, pageRequest.getClazzId());
        }
        qw.orderByAsc(User::getId);
        IPage<User> pageData = userMapper.selectPage(page, qw);
        List<User> records = pageData.getRecords();
        List<UserResponse> userResponses = UserConvert.INSTANCE.users2Responses(records);
        return RestResponse.success(new PageResponse<>(userResponses, pageData.getTotal(), pageRequest.getPage(), pageRequest.getLimit()));
    }

    @Override
    public List<Info> queryUserNamesByIds(List<Long> ids) {
        if (ids.size() == 0) {
            return new ArrayList<>();
        }
        return userMapper.queryUserNamesByIds(ids);
    }

    @Override
    public RestResponse<List<Info>> queryAllUsersByRole(RoleEnum roleEnum) {
        return RestResponse.success(userMapper.queryAllUsersByRole(roleEnum.getCode()));
    }

    @Override
    public List<Info> queryUserInfosNotInIds(List<Long> ids) {
        LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
        qw.notIn(User::getId, ids);
        qw.eq(User::getRole, RoleEnum.teacher.getCode());
        qw.orderByAsc(User::getId);
        List<User> users = userMapper.selectList(qw);
        return UserConvert.INSTANCE.users2Infos(users);
    }

    @Override
    public List<Long> getClassStudentIdsById(Long classid) {
        LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
        qw.eq(User::getRole, RoleEnum.student.getCode());
        qw.eq(User::getClazzId, classid);
        return userMapper.selectList(qw).stream().map(User::getId).collect(Collectors.toList());
    }

    @Override
    public RestResponse<Boolean> isPasswordValid() {
        String token = httpServletRequest.getHeader("Authorization");
        User currentUser = redisCache.getCurrentUser(token);
        return RestResponse.success(MDUtil.compare("123456", currentUser.getPassword()));
    }
}
